/*
 *
 * Copyright (c) 2023 - future
 * @author fzh
 * @email e_341877120_mail@163.com
 * @link https://mvnrepository.com/search?q=io.github.xrfzh.cn
 *
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package cn.xrfzh.system.common.utils;

import cn.hutool.core.date.DatePattern;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;

import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.Map;
import java.util.TimeZone;

/**
 * 使用Jackson完成JSON操作
 */
public class JsonUtil {

	private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

	private static final JavaType MAP_TYPE = OBJECT_MAPPER.getTypeFactory().constructParametricType(Map.class,
			String.class, Object.class);

	static {
		// 设置转换时日期格式
		OBJECT_MAPPER.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
		OBJECT_MAPPER.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
		// 全局配置序列化返回 JSON 处理
		SimpleModule simpleModule = new SimpleModule();
		// 序列化时 将Long类型转为 String 因为前端数字是number 精度为16位 而雪花算法生成的id为19位
		simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
		OBJECT_MAPPER.registerModule(simpleModule);
		// 字段为null时不参与序列化
		OBJECT_MAPPER.setSerializationInclusion(Include.NON_NULL);
		// json或map转bean忽略没有的字段 与@JsonIgnoreProperties(ignoreUnknown = true) 相同
		OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		OBJECT_MAPPER.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
		// 封装类型 Long ==> String
		simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
		simpleModule.addSerializer(LocalDateTime.class,
				new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
		simpleModule.addDeserializer(LocalDateTime.class,
				new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
		simpleModule.addSerializer(LocalDate.class,
				new LocalDateSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
		simpleModule.addDeserializer(LocalDate.class,
				new LocalDateDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
		simpleModule.addSerializer(LocalTime.class,
				new LocalTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
		simpleModule.addDeserializer(LocalTime.class,
				new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
		OBJECT_MAPPER.registerModule(simpleModule);
		OBJECT_MAPPER.setDateFormat(new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN));
		OBJECT_MAPPER.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
	}

	/**
	 * 实体类转换为json字符串
	 */
	public static String objectToJson(Object obj) {
		try {
			return OBJECT_MAPPER.writeValueAsString(obj);
		}
		catch (JsonProcessingException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 字符串集合转换为json字符串 为了避免对list元素中的str再次进行处理从而导致转换结果不可用
	 * @param stringsList 字符串集合
	 * @return
	 */
	public static String objectToJson(Collection<String> stringsList) {
		if (stringsList == null) {
			return "[]";
		}
		StringBuilder builder = new StringBuilder();
		builder.append("[");
		for (String s : stringsList) {
			builder.append(s);
			builder.append(",");
		}
		if (stringsList.size() > 0) {
			builder.deleteCharAt(builder.length() - 1);
		}
		builder.append("]");
		return builder.toString();
	}

	/**
	 * 可以转换普通类型，如User、Card等
	 * @param jsonStr json字符串
	 * @param beanClass JavaBean
	 * @return T
	 */
	public static <T> T string2Bean(String jsonStr, Class<T> beanClass) {
		try {
			return OBJECT_MAPPER.readValue(jsonStr, beanClass);
		}
		catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 可以转换为带有泛型的类，如User<Person>等，也可以转换带泛型的类，比如List<T>、Map<K,V>、Xxx<T>等
	 * @param jsonStr json字符串
	 * @param javaType 转换后的类型
	 * @return T
	 */
	public static <T> T string2Bean(String jsonStr, JavaType javaType) {
		try {
			return OBJECT_MAPPER.readValue(jsonStr, javaType);
		}
		catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 可以转换为带有泛型的类，如User<Person>等，也可以转换带泛型的类，比如List<T>、Map<K,V>、Xxx<T>等
	 * @param jsonStr json字符串
	 * @param beanClass JavaBean
	 * @param parametricTypes 泛型的具体类型
	 * @return T
	 */
	public static <T> T string2Bean(String jsonStr, Class beanClass, Class... parametricTypes) {
		try {
			JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructParametricType(beanClass, parametricTypes);
			return OBJECT_MAPPER.readValue(jsonStr, javaType);
		}
		catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 将 Map 转换为 JavaBean
	 * @param map 被转换的map
	 * @param beanClass JavaBean
	 * @return
	 */
	public static <T> T map2pojo(Map map, Class<T> beanClass) {
		return OBJECT_MAPPER.convertValue(map, beanClass);
	}

	/**
	 * 将 Map 转换为 JavaBean
	 * @param map 被转换的map
	 * @param javaType 类型
	 * @return
	 */
	public static <T> T map2pojo(Map map, JavaType javaType) {
		return OBJECT_MAPPER.convertValue(map, javaType);
	}

	/**
	 * 将 Map 转换为 JavaBean
	 * @param map 被转换的map
	 * @param type 类型
	 * @return
	 */
	public static <T> T map2pojo(Map map, Type type) {
		return map2pojo(map, OBJECT_MAPPER.getTypeFactory().constructType(type));
	}

}
